像写文章一样使用 Kotlin

    不知道大家有没有看到过下面的函数调用:

    这样的感觉就好像在写文章,没有括号,让语言的表现力进一步增强。Groovy 和 Scala 就有这样的特性,那么 Kotlin 呢?

    1. ...
    2. }

    如果你在 Kotlin 中写下了这样的代码,你可能觉得很自然,不过你有没有想过 0..10 究竟是个什么?

    “是个 IntRange 啊,这你都不知道。”你一脸嫌弃的回答道。

    是啊,确实是个 IntRange,不过为什么是 0..10 返回个 IntRange,而不是 0->10 呢?

    “我靠。。这是出厂设定,懂不懂。。”你开始变得更嫌弃了。。

    额,其实我想说的是,你知不知道这其实是个运算符重载?!

    1. public final operator
    2. : kotlin.ranges.IntRange {
    3. ...
    4. }

    “毕竟运算符是有限的吧?如果说我想给 Person 增加个 say 方法,不带括号那种,怎么办?” 你不以为然地说。

    这个嘛。。当然也是可以哒!

    1. infix fun 说(word: String){
    2. println("\"$name 说 $word\"")
    3. }
    4. }
    5. fun main(args: Array<String>) {
    6. val 老张 = Person("老张")
    7. }

    这段代码执行结果是:

    这个看上去有有点儿意思不?代码跟输出是一样滴!有人会说,中文变量和函数名真的大丈夫?是滴,全然大丈夫,这是因为 Java、Kotlin 的字节码都采用 Unicode,中文确实是可以的——不过,Java 还支持中文包名和文件名,这在 Kotlin 当中还是有些问题的。

    接着说,通常我们的方法传参是需要括号的,为什么这里不需要了呢?因为 infix 这个关键字!这里跟 Scala 和 Groovy 不同,Kotlin 只有显示的声明为 infix 的只有一个参数的方法才可以这么玩,如果你不显示声明,想去括号门儿都没有。

    好,抛开老张的例子不谈,毕竟真正生产环境下,谁会去用中文呢。什么情况下我们需要 infix?当然是 DSL 中。我们看一段 Gradle 配置:

    1. apply plugin: 'kotlin'

    看上去很有表现力是吧,即使你不懂 groovy 语法,也能直接看懂这句话就是使用 kotlin 插件。可它本质上还是句 groovy 代码,所以它的结构是怎样的呢?

    1. void apply(Map<String, ?> config);
    1. apply ([plugin: 'kotlin', 宝宝: "不开心"])

    不过这样虽然多传了一个键值对,不过由于 gradle 并不关心 “宝宝”,所以 “宝宝:不开心”那也没有办法了,说了也白说。哈哈。

    前面的 DSL 是 groovy 版本的,再回到 Kotlin 当中,如果我们编写 DSL 代码,据说 Kotlin 版本的 gradle 也已经在开发中了,那么我们猜猜它会长成啥样?

    用 Kotlin 的 K to V 的方式传入一个 Pair。这里的 apply 的声明就应该是:

    1. infix fun apply(config: Map<String, Any>)

    很丑?没关系,我们为什么不直接搞一个方法叫做 applyPlugin 呢?

      于是:

      1. applyPlugin "kotlin"

      当然,作为静态语言,与 groovy 当然不能照搬了,所以最理想的实现肯定是强类型约束,比如

      不过,这个我们就不谈了,跑题了。